//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Parsing
{
    /// <summary>
    /// Summary description for GenericParser.
    /// </summary>
    class GenericParser
    {
        internal Token CurrentToken;
        internal Token NextToken()
        {
            Contract.Assert(CurrentToken != null);
            var result =  NextToken(CurrentToken);

            return result;
        }
        public IEnumerable<Token> GetTokens()
        {
            Token t = NextToken();
            while (t != null)
            {
                yield return t;
                SetCurrentToken(t);
                t = NextToken();
            }
        }
        internal Token NextToken(Token n)
        {
            Contract.Requires(n != null);
            if (n.Next != null)
                return n.Next;
            Token t;
            try
            {
                t = _lexer.NextToken();
            }
            catch (Exception e)
            {
                Contract.Assert(CurrentPragma != null);
                throw new ParsingException(CurrentPragma, e.Message);
            }
            if (t == null)
            {
                return null;
            }
            n.Next = t;
            return t;
        }
        internal Lexer _lexer = new Lexer();
        protected void Expect(TokenId type)
        {
            Token t = NextToken();
            if (t == null)
                throw new UnexpectedTokenException(CurrentPragma, type, t);
            if (t.Type != type)
                throw new UnexpectedTokenException(CurrentPragma, type, t);
            CurrentToken = t;
        }
        protected CodeLinePragma CurrentPragma
        {
            get
            {
                return getPragma(CurrentToken);
            }
        }

        private CodeLinePragma getPragma(Token t)
        {
            return new CodeLinePragma(_fileName, t.Position);
        }
        protected CodeLinePragma CurrentEndPragma
        {
            get
            {
                return new CodeLinePragma(_fileName, CurrentToken.Position);
            }
        }
        protected CodeLinePragma CurrentFullPragma
        {
            get
            {
                CodeLinePragma r = CurrentPragma;
                //r.Terminate(CurrentEndPragma);
                return r;
            }
        }
        internal string _fileName;

        public bool NextIs(TokenId t)
        {
            Token n = NextToken();
            if (n == null)
                return false;
            if (n.Type == t)
                return true;
            return false;
        }

        public TokenId NextTokenType()
        {
            Token n = NextToken();
            if (n == null)
                return TokenId.StartToken;
            return n.Type;
        }
        protected void Eat(TokenId t)
        {
            CurrentToken = NextToken();
            Contract.Assert(CurrentToken.Type == t);
        }
        public bool Has(TokenId t)
        {
            Token n = NextToken();
            if (n == null)
            {
                return false;
            }
            if (n.Type == t)
            {
                SetCurrentToken(n);
                return true;
            }
            return false;
        }

        internal virtual void SetCurrentToken(Token n)
        {
            CurrentToken = n;
        }
        internal IdentifierBase Identifier()
        {
            Token t = NextToken();
            if (t is IdentifierBase)
            {
                CurrentToken = t;
                return (IdentifierBase)t;
            }
            throw new UnexpectedTokenException(CurrentPragma, TokenId.Identifier, t);
        }
    }
}
